#pragma once

#include "../../../Libs/headers.default.h"
#include "../../../Libs/headers.cv.h"

#include "HiBoost.Instance.h"
#include "HiBoost.Data.h"

using	namespace	std;

class CHiBoostImageLayer
{
public:
	class CPixRef
	{
	public:
		int index;
		int layer_ix, layer_iy;
		double layer_fx, layer_fy;
		double original_fx, original_fy;
		//double gradient_orientation;
		//double original_scale;

	public:
		static bool CompareBy_X_Y(const CPixRef& a, const CPixRef& b);
	};

public:
	int Scaled_W, Scaled_H;
	double BaseImageLayerScale;
	CZoomConfig ZoomConfig;
public:
	CImg<int> imgScaled;
	CSimpleTypeArray<double> matGradientOrientation;
public:
	int PixelAmount;
	CSimpleTypeArray<int> PixelList;
public:
	CSimpleTypeArray<CPixRef> PixRefList;
	int X_Amount;
	CSimpleTypeArray<int> X_StartList;

protected:
	static const CPixRef* _MySearch_Y(const CPixRef* Hd, const CPixRef* Tl, int KeyY);
public:
	static int ComputePixelDistance(int dx, int dy);
public:
	CHiBoostImageLayer();
	virtual size_t GetMemoryUsage() const;
public:
	void Clear();
	void SetImage(
		const CZoomableImage& ZoomImage,
		double xScale, double yScale,
		CImagePixelSampler_EdgeAndRandom* pFixedIPS,
		double GradientComputing_GaussianSigma,
		bool GradientComputing_fUseSignedOrientation);
private:
	void DrawPoints(CImg<int>& DstImage) const;
public:
	void DrawPixSet(CImg<int>& DstImage) const;
public:
	void BuildPixRef_OriginalCoordinate(CPixRef& DstPixRef, double original_fx, double original_fy) const;
	void BuildPixRef_LayerCoordinate(CPixRef& DstPixRef, double layer_fx, double layer_fy) const;
public:
	double GetGradientOrientation_IntLayerCoordinate(int layer_ix, int layer_iy) const;
public:
	const CPixRef* FindNearestSampledPixel_OriginalCoordinate(double original_fx, double original_fy) const;
	const CPixRef* FindNearestSampledPixel_LayerCoordinate(double layer_fx, double layer_fy) const;
};

class CHiBoostLayerRecord
{
public:
	int ScaleIndex;
	int oW, oH, oWH;
	CZoomConfig ZoomConfig;
public:
	int Amount_Record;
	int Length_Record;
	CSimpleTypeArray<int> matNearestRecord;
	CSimpleTypeArray<double> matRecordScore;

public:
	void myInit(
		const CZoomableImage& ZoomImage,
		int ScaleIndex, double ScaleFactor,
		CHiBoostNodeSetAppearanceIPFE& nsa,
		CImagePixelSampler_EdgeAndRandom* pPixelSampler,
		CSimpleTypeArray<CBinaryClassifier*>& FixedBcPtrList
		);
	double GetAppearanceScore_OriginalCoordinate(double original_fx, double original_fy, int NodeIndex);
};

class CHiBoostImageEntity
{
public:
	class CConfig
	{
	public:
		hi_boost::CHiBoostExampleSettings* pExampleSettings;
		//CHiBoostExampleConfig* pHiBoostExampleConfig;
	public:
		double ScaleFactor_AppearanceModel;
		int IPFE_CacheSize;
		CSimpleTypeArray<CBinaryClassifier*> FixedBcPtrList;
	public:
		double ScaleFactor_PerceptronParser;
		CImagePixelSampler_EdgeAndRandom* pIPS_ForInference;
		CImagePixelSampler_EdgeAndRandom* pIPS_ForAppearance;
		double GradientComputing_GaussianSigma;
		bool GradientComputing_fUseSignedOrientation;
		int LayerMinWidth;
		int LayerMinHeight;
	};

public:
	class CAppearanceScoreRecord
	{
	public:
		int NodeIndex;
		int QueryX;
		int QueryY;
		int Index_Scale;
		double Score;

	public:
		bool operator< (const CAppearanceScoreRecord& AnotherInstance) const;
		bool operator== (const CAppearanceScoreRecord& AnotherInstance) const;
	};

public:
	static CConfig s_Config;
public:
	static const int s_fFindNearestSampledPixel = 0;
	static const int s_fUseAppearanceScoreCache = 1;
	static const int s_fUseGlobalRecordCache = 0;
public:
	int Original_W;
	int Original_H;
	string strFN_ImageCache;
	CImg<int> imgSource;
	CZoomableImage ZoomImage;
	int Tag;
protected:
	int _Last_nsa_NodeIndex;
public:
	CHiBoostNodeSetAppearanceIPFE nsa;
	CImagePyramidPositionFeatureExtractor* pIPPFE;
public:
	CHiBoostImageLayer CurrentImageLayer;
	int Amount_PixRef;
	const CHiBoostImageLayer::CPixRef* PtrPixRef;
public:
	int Amount_QueryReceived_CurrentLayer;
	int Amount_CalculationMade_CurrentLayer;
	int Amount_QueryReceived_FullImage;
	int Amount_CalculationMade_FullImage;
	set<CAppearanceScoreRecord> AppearanceScoreHistory;
public:
	CSimpleTypeArray<CHiBoostImageLayer::CPixRef> ParsedLeafInstanceList;
public:
	CSimpleTypeArray<CHiBoostLayerRecord*> List_PtrLayerRecord;
public:
	class CGtNodeInst
	{
	public:
		double x, y, rot, scale;
	};
	CSimpleTypeArray<CSimpleTypeArray<CGtNodeInst>> matGtNodeInst;
public:
	CTimer timAppCalc;

public:
	CHiBoostImageEntity();
	virtual ~CHiBoostImageEntity();
	virtual size_t GetMemoryUsage() const;
	//void InitSettings(const CConfig* pFixedConfig);
	void SetImage(string strFN_SourceImage, string strImageHashName, bool fIsFlipped);
	void SetImage(const CImg<int>& SourceImage, string strImageHashName, bool fIsFlipped);
public:
	void ReadParsedLeafInstances(const CHiBoostNodeInstanceBoxSet* pSrcParsedInstance);
	//void ReadGroundTruth(string strFN_GroundTruth);
public:
	bool SetCurrentImageLayer(int LayerIndex);
	bool SetCurrentImageLayer_ByScale(double Scale);
public:
	const CHiBoostImageLayer::CPixRef* FindNearestSampledPixel_OriginalCoordinate(double original_fx, double original_fy) const;
	const CHiBoostImageLayer::CPixRef* FindNearestSampledPixel_LayerCoordinate(double layer_fx, double layer_fy) const;
public:
	void ClearAppearanceScoreCountLog_CurrentLayer();
	void ClearAppearanceScoreCountLog_FullImage();
public:
	void SetFN_ImageCache(string strFN_NewImageCache);
public:
	double GetAppearanceScore_LayerCoordinate(double layer_fx, double layer_fy, double inference_scale, int NodeIndex);
public:
	void RefreshIPPFE(int NodeIndex);
};

